package com.rr.sc.dao.impl.hibernate;

import java.util.Collection;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;

public class AbstractDao {
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
	return sessionFactory;
    }

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
	this.sessionFactory = sessionFactory;
    }

    public Session getCurrentSession() {
	return getSessionFactory().getCurrentSession();
    }

    @SuppressWarnings("rawtypes")
    public List find(String queryString) throws DataAccessException {
	return find(queryString, (Object[]) null);
    }

    @SuppressWarnings("rawtypes")
    public List find(String queryString, Object value) throws DataAccessException {
	return find(queryString, new Object[] { value });
    }

    @SuppressWarnings("rawtypes")
    public List find(final String queryString, final Object... values) throws DataAccessException {
	Query queryObject = getCurrentSession().createQuery(queryString);
	if (values != null) {
	    for (int i = 0; i < values.length; i++) {
		queryObject.setParameter(i, values[i]);
	    }
	}
	return queryObject.list();
    }

    @SuppressWarnings("rawtypes")
    public List findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException {
	return findByNamedParam(queryString, new String[] { paramName }, new Object[] { value });
    }

    @SuppressWarnings("rawtypes")
    public List findByNamedParam(final String queryString, final String[] paramNames, final Object[] values) throws DataAccessException {
	if (paramNames.length != values.length) {
	    throw new IllegalArgumentException("Length of paramNames array must match length of values array");
	}
	Query queryObject = getCurrentSession().createQuery(queryString);
	if (values != null) {
	    for (int i = 0; i < values.length; i++) {
		applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
	    }
	}
	return queryObject.list();
    }

    /**
     * Apply the given name parameter to the given Query object.
     * 
     * @param queryObject
     *            the Query object
     * @param paramName
     *            the name of the parameter
     * @param value
     *            the value of the parameter
     * @throws HibernateException
     *             if thrown by the Query object
     */
    @SuppressWarnings("rawtypes")
    protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value) throws HibernateException {

	if (value instanceof Collection) {
	    queryObject.setParameterList(paramName, (Collection) value);
	} else if (value instanceof Object[]) {
	    queryObject.setParameterList(paramName, (Object[]) value);
	} else {
	    queryObject.setParameter(paramName, value);
	}
    }

    public void saveOrUpdate(Object object) {
	if (getCurrentSession().contains(object)) {
	    getCurrentSession().saveOrUpdate(object);
	} else {
	    Object o = getCurrentSession().merge(object);
	    getCurrentSession().saveOrUpdate(o);
	    object = o;
	}
    }
}
